-- luajit opus2opa.lua input.opus input.wav output.opa

local floor = math.floor
local char = string.char

local f = io.open(arg[1], "rb")
local s = f:read "*a"
f:close()

f = io.open(arg[2], "rb")
f:seek("set", 0x16)
local channels = f:read(1):byte(1)
local p = 0x24
local n
while true do
	f:seek("set", p)
	local t = f:read(4)
	if not t or t == "" then
		error "ERROR: read wav eof"
	end
	local a,b,c,d = f:read(4):byte(1,4)
	n = a + b*0x100 + c*0x10000 + d*0x1000000
	if t == "data" then
		if n == 0 then
			n = f:seek("end", 0) - p - 8
		end
		break
	end
	p = p + 8 + n
end

local i = 0
local function readIntBe()
	local v = s:byte(i+1) * 0x1000000 + s:byte(i+2) * 0x10000 + s:byte(i+3) * 0x100 + s:byte(i+4)
	i = i + 4
	return v
end

local t = {}
while i < #s do
	local v = readIntBe()
	if v >= 2048 then
		error("ERROR: too big packet(payload): " .. v)
	end
	i = i + 4 + v
	t[#t + 1] = v
end
if i > #s then
	error("ERROR: packet(payload) overflow: " .. i)
end

n = n / 4
f = io.open(arg[3], "wb")
f:write(channels == 1 and "OPA1" or "OPA2")
f:write(char(n % 0x100))
f:write(char(floor(n / 0x100) % 0x100))
f:write(char(floor(n / 0x10000) % 0x100))
f:write(char(floor(n / 0x1000000)))
p = floor((312 + n + 5760 - 1) / 5760)
if p ~= #t then
	error("ERROR: unmatched packet(payload) count: wav=" .. p .. ", opus=" .. #t)
end
local last = 0
for _, n in ipairs(t) do
	local d = n - last
	if d >= -124 and d <= 123 then
		f:write(char(d + 0x84))
	else
		f:write(char(floor(n / 256)))
		f:write(char(n % 256))
	end
	last = n
end
i = 0
for _, n in ipairs(t) do
	i = i + 8
	f:write(s:sub(i+1, i+n))
	i = i + n
end
f:close()
print("done! " .. p .. " packets, " .. n .. " frames")
